#include "kernel.h"
extern "C"{
void kernelone(
		IN_TYPE offset1[OFFSET_LEN],IN_TYPE adj1[ADJ_LEN],
		IN_TYPE offset2[OFFSET_LEN],IN_TYPE adj2[ADJ_LEN],
		IN_TYPE cand1[CAN_LEN],CAN_TYPE cand2[CAN2_LEN],
		IN_TYPE size1,IN_TYPE size2,
		IN_TYPE pid1,
		IN_TYPE out_buf[OUT_LEN],IN_TYPE paras[PARA_LEN]
		)
{
#pragma HLS INTERFACE m_axi port=cand1 offset=slave bundle=gmem0
#pragma HLS INTERFACE m_axi port=cand2 offset=slave bundle=gmem1
#pragma HLS INTERFACE m_axi port=out_buf offset=slave bundle=gmem2
#pragma HLS INTERFACE m_axi port=paras offset=slave bundle=gmem7

#pragma HLS INTERFACE m_axi port=offset1 offset=slave bundle=gmem3
#pragma HLS INTERFACE m_axi port=adj1 offset=slave bundle=gmem4
#pragma HLS INTERFACE m_axi port=offset2 offset=slave bundle=gmem5
#pragma HLS INTERFACE m_axi port=adj2 offset=slave bundle=gmem6

#pragma HLS INTERFACE s_axilite port=offset1 bundle=control
#pragma HLS INTERFACE s_axilite port=adj1 bundle=control
#pragma HLS INTERFACE s_axilite port=offset2 bundle=control
#pragma HLS INTERFACE s_axilite port=adj2 bundle=control

#pragma HLS INTERFACE s_axilite port=cand1 bundle=control
#pragma HLS INTERFACE s_axilite port=cand2 bundle=control
#pragma HLS INTERFACE s_axilite port=out_buf bundle=control
#pragma HLS INTERFACE s_axilite port=paras bundle=control
#pragma HLS INTERFACE s_axilite port=size1 bundle=control
#pragma HLS INTERFACE s_axilite port=size2 bundle=control
#pragma HLS INTERFACE s_axilite port=pid1 bundle=control
#pragma HLS INTERFACE s_axilite port=return bundle=control

	IN_TYPE size_c1 = 0;
	IN_TYPE size_c2 = 0;
	static IN_TYPE preid1;
	//static IN_TYPE out_buffer[25600];
	static IN_TYPE cand1_buffer[1024][16];
#pragma HLS ARRAY_PARTITION variable=cand1_buffer complete dim=1
	//static IN_TYPE cand2_buffer[4][12500];
	//static IN_TYPE cand2_cache[35000];
//#pragma HLS RESOURCE variable=cand2_cache core=RAM_T2P_URAM
	static IN_TYPE cand1_count = 0;
	static IN_TYPE cand1_bf_count[1024];
#pragma HLS ARRAY_PARTITION variable=cand1_bf_count complete dim=1
	static IN_TYPE cand2_bf_count = 0;
	static IN_TYPE out_count=0;
	static IN_TYPE cand2_count = 0;
	static IN_TYPE out_iter = 0;
	IN_TYPE i,j,tmp,begin,end,adj_size,iter,jj,kk,index,efcount,efoff;
	int bid,off;
	CAN_TYPE tmpblock,tmpblock2,tmpblock3;

	size_c1 = 0;
	size_c2 = 0;
	preid1 = 13;
	cand1_count = 0;
	cand2_bf_count = 0;
	out_count=0;
	cand2_count=0;
	out_iter = 0;
	i=0;
	j=0;
	begin=0;
	end=0;
	adj_size=0;
	iter=0;
	jj=0;
	kk=0;
	index = 0;
	size_c1 = size1;
	size_c2 = size2;
	preid1 = pid1;
	IN_TYPE max_size = 0;
	for(;cand1_count<size_c1;){
		//cout<<"a new iteration"<<endl;
		INITIAL2:for(i=0;i<1024;i++){
			#pragma HLS UNROLL
			cand1_bf_count[i]=0;
		}
		CAND1_LOAD_OUTTER:for(i=0;i<1024 && cand1_count<size1;i++){
			tmp = cand1[cand1_count];
			cand1_count++;
			cand1_buffer[i][0]=tmp;
			cand1_bf_count[i]++;
			if(preid1==3){
				begin = offset1[tmp];
				end = offset1[tmp+1];
				adj_size = end - begin;
				if(adj_size > max_size){
					max_size = adj_size;
				}
				READ_ADJ1:for(iter=0;iter<adj_size;iter++){
					cand1_buffer[i][cand1_bf_count[i]] = adj1[iter+begin];
					cand1_bf_count[i]++;
				}
			}else{
				begin = offset2[tmp];
				end = offset2[tmp+1];
				adj_size = end - begin;
				if(adj_size > max_size){
					max_size = adj_size;
				}
				READ_ADJ2:for(iter=0;iter<adj_size;iter++){
					cand1_buffer[i][cand1_bf_count[i]] = adj2[iter+begin];
					cand1_bf_count[i]++;
				}
			}
		}

		paras[0] = cand1_count;
		paras[1] = max_size;

		for(i=0;i<1024;i++){
			for( jj = 1;jj < cand1_bf_count[i] ; jj++ ){
				bid = cand1_buffer[i][jj] / 8;
				off = cand1_buffer[i][jj] % 8;
				tmpblock = cand2[bid];
				tmpblock2 = 1<<(7-off);
				//std::cout << "tmpblock is " << (int)tmpblock << " and tmpblock2 is " << (int)tmpblock2 << std::endl;
				tmpblock3 = tmpblock&tmpblock2;
				if(tmpblock3 == tmpblock2){
					out_buf[out_count] = cand1_buffer[i][0];
					out_count++;
					out_buf[out_count] = cand1_buffer[i][jj];
					out_count++;
				}
			}
		}
	}

	efcount = out_count % 64;
	efoff = 64 - efcount + 1;
	for(i=0;i<efoff;i++){
		out_buf[out_count] = END_FLAG;
		out_count++;
	}

	paras[2] = out_count;
	for(i=3;i<64;i++){
		paras[i] = END_FLAG;
	}
	//cout<<"out_size "<<out_count<<endl;
}
}
